Mineração de Dados 4
Os tópicos abordados serão:
pacote
ggplot2para análise gráfica: estrutura e exemplos de aplicação;métodos de redução de dimensão: análise de correlação, análise de componentes principais;
análise de componentes principais para identificação de agrupamentos e para previsão.
Vamos instalar os pacotes necessários.
install.packages("ggplot2") # pacote para análise gráfica
install.packages("gridExtra") # pacote com função que permite múltiplos gráficos em uma mesma janela no ggplot2
install.packages("reshape2") # pacote para transformação de dados
install.packages("ggcorrplot") # pacote para visualizaçao de matrizes de correlações no ggplot2
install.packages("factoextra") # pacote para visualização de resultados da análise de componentes principaisVamos utilizar também o pacote stringr, instalado anteriormente.
Exemplo 5 - Qualidade de vinhos (2)
Voltaremos ao banco de dados sobre características de vinhos, que contém informações sobre variações de vinhos tintos e brancos do vinho português “Vinho Verde”.
Novamente, os dados podem ser obtidos em http://archive.ics.uci.edu/ml/datasets/Wine+Quality e já foram estudados por Cortez et al. (2009).
As variáveis são:
- fixed acidity;
- volatile acidity
- citric acid;
- residual sugar;
- chlorides;
- free sulfur dioxide;
- total sulfur dioxide
- density
- pH;
- sulphates;
- alcohol;
- quality (score between 0 and 10) (baseada em dados sensoriais).
Importando o banco de dados
Vamos importar o banco de dados, porém agora analisaremos os dados de vinho branco, em vez de vinho tinto.
Arquivo com extensão .csv separado por ponto-e-vírgula
Vamos importar a base de dados de vinho tinto.
white <- read.csv("http://im.ufrj.br/~joao/cienciadedados/winequality-white.csv",sep=";")
head(white) # vislumbre dos dados
names(white) # # nomes das colunas do objeto (variáveis)## fixed.acidity volatile.acidity citric.acid residual.sugar chlorides
## 1 7.0 0.27 0.36 20.7 0.045
## 2 6.3 0.30 0.34 1.6 0.049
## 3 8.1 0.28 0.40 6.9 0.050
## 4 7.2 0.23 0.32 8.5 0.058
## 5 7.2 0.23 0.32 8.5 0.058
## 6 8.1 0.28 0.40 6.9 0.050
## free.sulfur.dioxide total.sulfur.dioxide density pH sulphates alcohol
## 1 45 170 1.0010 3.00 0.45 8.8
## 2 14 132 0.9940 3.30 0.49 9.5
## 3 30 97 0.9951 3.26 0.44 10.1
## 4 47 186 0.9956 3.19 0.40 9.9
## 5 47 186 0.9956 3.19 0.40 9.9
## 6 30 97 0.9951 3.26 0.44 10.1
## quality
## 1 6
## 2 6
## 3 6
## 4 6
## 5 6
## 6 6
## [1] "fixed.acidity" "volatile.acidity" "citric.acid"
## [4] "residual.sugar" "chlorides" "free.sulfur.dioxide"
## [7] "total.sulfur.dioxide" "density" "pH"
## [10] "sulphates" "alcohol" "quality"
Pacote ggplot2
O
ggplot2(Wickham 2016) é um pacote de visualização de dados para o R que tem ganhados muitos adeptos nos útimos anos por permitir a confecção de gráficos flexíveis e sofisticados.É uma implementação da Grammar of Graphics (Wilkinson 2012): um esquema geral para visualização de dados que divide gráficos em componentes semânticos, como escalas e camadas.
Vamos prosseguir com uma análise exploratória dos dados utilizando o
ggplot2.
Análise exploratória da qualidade do vinho (quality)
Primeiramente, vamos chamar o pacote ggplot2.
A ideia do ggplot2 é que você construa gráficos por meio das mesmas componentes: um conjunto de dados, um sistema de coordenadas e geoms, que são a maneira como os dados serão representados, por exemplo, um histograma ou gráfico de dispersão.
Componentes estéticos (aesthetic) descrevem como as variáveis são mapeadas visualmente nos geoms; podem ser eixos, pontos, cores.
Inicialmente, vamos construir um histograma para as notas dos vinhos, variável que representa a qualidade (quality).
A função
aes() pode ser chamada dentro da função geom_histograma() em vez de na função ggplot().
Podemos modificas os eixos do histograma por meio das funções xlab() e ylab().
ggplot(white,aes(quality)) + geom_histogram(bins=7,col="white",fill="goldenrod") + xlab("Notas") + ylab("Frequência absoluta") + ggtitle("Histograma das notas dos vinhos")Podemos alterar os nomes nos eixos e título conjuntamente por meio da função labs(), além de incluir legendas e subtítulo.
ggplot(white,aes(quality)) +
geom_histogram(bins=7,col=1,fill="turquoise") +
labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)",caption="Figura: Histograma das notas dos vinhos dada por especialistas.") A função
theme() permite que mudemos a aparências de diversos elementos do gráfico.
Podemos ir acrescentando cada função (camada) ao objeto (gráfico) que queremos plotar e só depois plotá-lo.
histograma <- ggplot(white,aes(quality)) +
geom_histogram(bins=7,col=1,fill="firebrick") +
labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)")
histograma <- histograma + theme(axis.title.x=element_text(color=2,size=20,face="italic"),
axis.title.y=element_text(color=2,size=20,face="italic"),
axis.text.x=element_text(size=17),
axis.text.y=element_text(size=17))
histograma Vamos agora retirar a grade do histograma a alterar alguns parâmetros gráficos.
histograma <- ggplot(white,aes(quality)) +
geom_histogram(bins=7,col=1,fill="firebrick") +
labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)")
histograma <- histograma + theme(axis.title.x=element_text(color=2,size=20,face="italic"),
axis.title.y=element_text(color=2,size=20,face="italic"),
axis.text.x=element_text(size=17),
axis.text.y=element_text(size=17))
histogramaPodemos escolher temas pré-definidos para os gráficos.
histograma <- ggplot(white,aes(quality)) +
geom_histogram(bins=7,col=1,fill="firebrick") +
labs(x="Notas",y="Frequência absoluta",title="Histograma das notas dos vinho",subtitle="(Qualidade)")
histogramaExperimente theme_classic(), theme_linedraw(), theme_minimal() e theme_void().
Para fazer um histograma com a frequência relativa, podemos proceder como abaixo.
ggplot(white,aes(x=quality,y=..count../sum(..count..))) + geom_histogram(bins=7,col="white",fill="khaki") + labs(x="Notas",y="Frequência relativa") + theme_dark()Vamos fazer também um polígono de frequências para as notas dos vinhos.
ggplot(white,aes(quality)) + geom_freqpoly(bins=7,lwd=1) +
labs(x="Notas",y="Frequência absoluta") +
theme(axis.title=element_text(size=16),axis.text=element_text(size=12))Como a nota é uma variável discreta, pode ser útil, em vez de um histograma, fazer um gráfico de barras.
Vamos utilizar a função scale_*_discrete() mapeia valores discretos da variável em valores visuais.
ggplot(white,aes(quality)) + geom_bar(fill="mediumseagreen",col="mediumseagreen") +
labs(x="Notas",y="Frequência absoluta") + scale_x_discrete(limits=3:9)## Warning: Continuous limits supplied to discrete scale.
## Did you mean `limits = factor(...)` or `scale_*_continuous()`?
Análise exploratória das demais variáveis
Queremos construir histogramas em uma mesma janela. Para este fim, podemos utilizar a função grid.arrange() do pacote gridExtra (Auguie 2017).
Vamos chamá-lo.
Se quisermos plotar os gráficos plotados anteriormente em uma mesma janela, podemos proceder como abaixo.
histograma <- ggplot(white,aes(quality)) + geom_histogram(bins=7,col="white",fill="khaki") +
labs(x="Notas",y="Frequencia absoluta")
poligono <- ggplot(white,aes(quality)) + geom_freqpoly(bins=7,lwd=2) +
labs(x="Notas",y="Frequencia absoluta")
barras <- ggplot(white,aes(quality)) + geom_bar(fill="mediumseagreen",col="mediumseagreen") +
labs(x="Notas",y="Frequência absoluta") + scale_x_discrete(limits=3:9)## Warning: Continuous limits supplied to discrete scale.
## Did you mean `limits = factor(...)` or `scale_*_continuous()`?
Vamos fazer histogramas para cada uma das variáveis em uma mesma janela.
n <- dim(white)[2] # número de variáveis
graf <- list()
for(i in 1:n){
graf[[i]] <- local({ # solução para o problema de ambiente: isola o bloco do for
i <- i
ggplot(white,aes(white[,i])) + geom_histogram(bins=7,col="black",fill="lightsteelblue1") +
labs(x=names(white)[i],y="Frequência")
})
}
grid.arrange(grobs=graf,nrow=3,ncol=4) # grobs permite colocar a lista com todos os gráficosQueremos agora calcular algumas medidas a respeito das variáveis do banco de dados, como média, mediana e desvio padrão.
Diferente do que foi feito anteriormente - em que utilizando o comando for para varrer os vetores e calcular as medidas - agora vamos utilizar a função apply().
A função apply() aplica uma função às linhas ou colunas de uma matriz ou data frame. Na maioria das situações, é mais eficiente que utilizar o comando for.
## fixed.acidity volatile.acidity citric.acid
## 6.85478767 0.27824112 0.33419151
## residual.sugar chlorides free.sulfur.dioxide
## 6.39141486 0.04577236 35.30808493
## total.sulfur.dioxide density pH
## 138.36065741 0.99402738 3.18826664
## sulphates alcohol quality
## 0.48984688 10.51426705 5.87790935
## fixed.acidity volatile.acidity citric.acid
## 0.843868228 0.100794548 0.121019804
## residual.sugar chlorides free.sulfur.dioxide
## 5.072057784 0.021847968 17.007137325
## total.sulfur.dioxide density pH
## 42.498064554 0.002990907 0.151000600
## sulphates alcohol quality
## 0.114125834 1.230620568 0.885638575
## fixed.acidity volatile.acidity citric.acid
## 6.80000 0.26000 0.32000
## residual.sugar chlorides free.sulfur.dioxide
## 5.20000 0.04300 34.00000
## total.sulfur.dioxide density pH
## 134.00000 0.99374 3.18000
## sulphates alcohol quality
## 0.47000 10.40000 6.00000
## Média Mediana Desvio.padrão
## fixed.acidity 6.85478767 6.80000 0.843868228
## volatile.acidity 0.27824112 0.26000 0.100794548
## citric.acid 0.33419151 0.32000 0.121019804
## residual.sugar 6.39141486 5.20000 5.072057784
## chlorides 0.04577236 0.04300 0.021847968
## free.sulfur.dioxide 35.30808493 34.00000 17.007137325
## total.sulfur.dioxide 138.36065741 134.00000 42.498064554
## density 0.99402738 0.99374 0.002990907
## pH 3.18826664 3.18000 0.151000600
## sulphates 0.48984688 0.47000 0.114125834
## alcohol 10.51426705 10.40000 1.230620568
## quality 5.87790935 6.00000 0.885638575
Análise bidimensional
Vamos agora fazer uma análise exploratória investigar se existe associação aparente entre as características do vinho branco e sua qualidade.
Como a variável quality (notas) é discreta, box-plots podem oferecer uma melhor visualização.
graf <- list()
for(i in 1:11){
graf[[i]] <- local({
i <- i
ggplot(white,aes(x=as.factor(quality),y=white[,i])) +
geom_boxplot(fill="khaki",outlier.size=1) +
labs(x=names(white)[12],y=names(white)[i])
})
}
grid.arrange(grobs=graf,nrow=3,ncol=4)Vamos calcular a correlação entre as notas e as demais variáveis.
## fixed.acidity volatile.acidity citric.acid residual.sugar chlorides
## [1,] -0.1136628 -0.194723 -0.009209091 -0.09757683 -0.2099344
## free.sulfur.dioxide total.sulfur.dioxide density pH sulphates
## [1,] 0.008158067 -0.1747372 -0.3071233 0.09942725 0.05367788
## alcohol
## [1,] 0.4355747
Podemos ver que a maior correlação é com a variável álcool (alcohol). Vamos investigar, em particular, tal relação por meio do box-plot com alguns elementos a mais.
ggplot(white,aes(x=as.factor(quality),y=alcohol)) + geom_boxplot(fill="goldenrod2",outlier.color="red") + labs(x="Notas",y="Álcool") +
geom_jitter(position=position_jitter(0.2),col="red")A segunda variável com maior correlação (em valor absoluto) com as notas é a variável a densidade(density).
Vamos fazer um gráfico que mostre a relação entre as três variáveis: quality, alcohol e density.
ggplot(white,aes(x=alcohol,y=density,col=as.factor(quality))) +
geom_point(alpha=0.2,size=3) +
labs(x="Álcool",y="Densidade")A função scale_*_manual() mapeia manualmente valores da variável em valores visuais.
ggplot(white,aes(x=alcohol,y=density,col=as.factor(quality))) +
geom_point(alpha=0.2,size=3) +
labs(x="Álcool",y="Densidade") + scale_color_manual(values=heat.colors(7),name="Notas") A função
scale_*_gradientn() mapeia valores contínuos da variável em valores visuais por meio de uma palheta de cores.
ggplot(white,aes(x=alcohol,y=density,col=quality)) +
geom_point(alpha=0.2,size=3) +
labs(x="Álcool",y="Densidade") + scale_color_gradientn(colours=heat.colors(7),name="Notas") Por fim, vamos exportar este último gráfico para um arquivo. Inicialmente, vamos gerar um arquivo PDF.
Exportado gráficos
disper <- ggplot(white,aes(x=alcohol,y=density,col=quality)) +
geom_point(alpha=0.2,size=3) +
labs(x="Álcool",y="Densidade") + scale_color_gradientn(colours=heat.colors(7),name="Notas")
ggsave("C:/Users/joaob/OneDrive/Desktop/Output/Dispersao.pdf",plot=disper,device="pdf",width=7,height=5) # tamanho está em polegadasPode-se também exportar para arquivos com outras extensões. Para isto, basta escolher uma extensão diferente em device.
- Dicas sobre a confecção de gráficos podem ser vistas em https://rstudio.com/wp-content/uploads/2015/03/ggplot2-cheatsheet.pdf.
Redução de dimensão (análise de correlação)
Em geral, é muito comum encontrarmos em bancos de dados um número grande de variáveis.
É muito comum, neste contexto, que tais variáveis sejam correlacionadas; que forneçam, de certa forma, a mesma informação para um modelo preditivo ou de classificação, por exemplo.
Tais características dos dados podem levar a problemas como overfitting e problemas computacionais.
Para variáveis quantitativas, uma forma simples de verificar rendudâncias na informação é por meio de uma análise de correlação, como a feita anteriormente para os dados de vinho tinto.
Correlação para os dados de vinho branco
Primeiramente, vamos construir a matriz de correlação.
## fixed.acidity volatile.acidity citric.acid residual.sugar
## fixed.acidity 1.00000000 -0.02269729 0.289180698 0.08902070
## volatile.acidity -0.02269729 1.00000000 -0.149471811 0.06428606
## citric.acid 0.28918070 -0.14947181 1.000000000 0.09421162
## residual.sugar 0.08902070 0.06428606 0.094211624 1.00000000
## chlorides 0.02308564 0.07051157 0.114364448 0.08868454
## free.sulfur.dioxide -0.04939586 -0.09701194 0.094077221 0.29909835
## total.sulfur.dioxide 0.09106976 0.08926050 0.121130798 0.40143931
## density 0.26533101 0.02711385 0.149502571 0.83896645
## pH -0.42585829 -0.03191537 -0.163748211 -0.19413345
## sulphates -0.01714299 -0.03572815 0.062330940 -0.02666437
## alcohol -0.12088112 0.06771794 -0.075728730 -0.45063122
## quality -0.11366283 -0.19472297 -0.009209091 -0.09757683
## chlorides free.sulfur.dioxide total.sulfur.dioxide
## fixed.acidity 0.02308564 -0.0493958591 0.091069756
## volatile.acidity 0.07051157 -0.0970119393 0.089260504
## citric.acid 0.11436445 0.0940772210 0.121130798
## residual.sugar 0.08868454 0.2990983537 0.401439311
## chlorides 1.00000000 0.1013923521 0.198910300
## free.sulfur.dioxide 0.10139235 1.0000000000 0.615500965
## total.sulfur.dioxide 0.19891030 0.6155009650 1.000000000
## density 0.25721132 0.2942104109 0.529881324
## pH -0.09043946 -0.0006177961 0.002320972
## sulphates 0.01676288 0.0592172458 0.134562367
## alcohol -0.36018871 -0.2501039415 -0.448892102
## quality -0.20993441 0.0081580671 -0.174737218
## density pH sulphates alcohol
## fixed.acidity 0.26533101 -0.4258582910 -0.01714299 -0.12088112
## volatile.acidity 0.02711385 -0.0319153683 -0.03572815 0.06771794
## citric.acid 0.14950257 -0.1637482114 0.06233094 -0.07572873
## residual.sugar 0.83896645 -0.1941334540 -0.02666437 -0.45063122
## chlorides 0.25721132 -0.0904394560 0.01676288 -0.36018871
## free.sulfur.dioxide 0.29421041 -0.0006177961 0.05921725 -0.25010394
## total.sulfur.dioxide 0.52988132 0.0023209718 0.13456237 -0.44889210
## density 1.00000000 -0.0935914935 0.07449315 -0.78013762
## pH -0.09359149 1.0000000000 0.15595150 0.12143210
## sulphates 0.07449315 0.1559514973 1.00000000 -0.01743277
## alcohol -0.78013762 0.1214320987 -0.01743277 1.00000000
## quality -0.30712331 0.0994272457 0.05367788 0.43557472
## quality
## fixed.acidity -0.113662831
## volatile.acidity -0.194722969
## citric.acid -0.009209091
## residual.sugar -0.097576829
## chlorides -0.209934411
## free.sulfur.dioxide 0.008158067
## total.sulfur.dioxide -0.174737218
## density -0.307123313
## pH 0.099427246
## sulphates 0.053677877
## alcohol 0.435574715
## quality 1.000000000
Vamos criar um gráfico para a matriz de correlação utilizando o ggplot2 por meio da função geom_tile().
Como a entrada da função ggplot() precisamos de um data frame com três coluna correspondendo aos eixos x e y e às correlações.
Para este fim, utilizaremos a função melt() do pacote reshape2. Vamos chamá-lo.
Vamos agora transformar a matriz de correlaçao em um data frame.
## Var1 Var2 value
## 1 fixed.acidity fixed.acidity 1.00000000
## 2 volatile.acidity fixed.acidity -0.02269729
## 3 citric.acid fixed.acidity 0.28918070
## 4 residual.sugar fixed.acidity 0.08902070
## 5 chlorides fixed.acidity 0.02308564
## 6 free.sulfur.dioxide fixed.acidity -0.04939586
Vamos melhorar a visualização.
ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=11),axis.text.y=element_text(size=11)) +
scale_fill_gradientn(colours=heat.colors(20),name="Correlação") Vamos tentar de outra forma utilizando a função
scale_*_gradient2.
ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=11),axis.text.y=element_text(size=11)) +
scale_fill_gradient2(low="blue",high="red",mid="white",limit=c(-1,1)) Vamos fazer agora um gráfico mostrando somente a diagonal superior. O comando
coorde_fixed deixa as escalas dos eixos x e y na escala original.
corrm[lower.tri(corrm)] <- NA # NA na diagonal inferior
corrm2 <- melt(corrm,na.rm=TRUE) # data frame sem os NA
ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=9),axis.text.y=element_text(size=9),panel.background=element_blank()) +
scale_fill_gradient2(low="blue",high="red",mid="white",limit=c(-1,1)) + coord_fixed() Vamos fazer uma última versão com os valores incluídos por meio da função
geom_text().
corrm[lower.tri(corrm)] <- NA # NA na diagonal inferior
corrm2 <- melt(corrm,na.rm=TRUE) # data frame sem os NA
ggplot(corrm2,aes(x=Var1,y=Var2,fill=value)) + geom_tile() +
labs(x="",y="") + theme(axis.text.x=element_text(angle=45,hjust=1,size=9),axis.text.y=element_text(size=9),panel.background=element_blank()) +
scale_fill_gradient2(low="blue",high="red",mid="white",limit=c(-1,1)) + coord_fixed() + geom_text(aes(x=Var1,y=Var2,label=round(value,2)),size=2.5) O pacote
ggcorrplot (Kassambara 2019) é útil por simplificar a confecção dos gráficos para as correlações utilizando o ggplot2.
Vamos chamá-lo.
Vamos produzir alguns gráficos usando a matriz de correlação.
Redução de dimensão (análise de componentes principais)
A análise de componentes principais (ACP ou PCA, na sigla em inglês) é um método muito útil para redução de dimensão, principalmente quando o número de variáveis é muito alto.
O método é utilizado para variáveis quantitativas que são medidas na mesma escala.
Ele fornece variáveis que são combinações lineares de outras variáveis e que explicam a maior parte da variabilidade.
Em termos gerais, a PCA utiliza projeções para representar o conjunto de dados original, com muitas variáveis, em poucas variáveis.
Seja \(\Sigma\) uma matriz quadrada de dimensão \(n\times n\).
Um vetor \(\gamma\) de dimensão \(n\) não nulo é dito ser um autovetor de \(\Sigma\) se existe um escalar \(\lambda\) tal que \[\begin{align*} \Sigma\gamma &= \lambda\gamma\\ \Leftrightarrow(\Sigma - \lambda {\bf I})\gamma &= {\bf 0}\\ \Leftrightarrow |\Sigma - \lambda{\bf I}| &= 0. \end{align*}\]
O escalar \(\lambda\) é chamado autovalor e seu valor é encontrado a partir da equação \(|\Sigma - \lambda{\bf I}| = 0\), que é denominada equação característica.
O valor de \(\gamma\) associado a \(\lambda\) é encontrado então a partir da equação \((\Sigma - \lambda {\bf I})\gamma = {\bf 0}\).
Suponha que \(\Sigma\) seja uma matriz de covariância. Então, ela pode ser escrita como \[ \Sigma = \Gamma\Lambda\Gamma', \] em que \(\Gamma\) é uma matriz de dimensão \(n\times n\) cujas colunas são os autovetores da matriz \(\Sigma\) e \(\Lambda\) é uma matriz diagonal cujos elementos são os autovalores de \(\Sigma\) associados às colunas de \(\Gamma\).
O fato de \(\Sigma\) ser simétrica implica \(\Gamma'\Gamma={\bf I}\).
Autovalores e autovetores
Vamos considerar as duas variáveis no banco de dados de vinho branco com a maior correlação. Neste caso, density e residual.sugar.
## [1] 0.8389665
Como as escalas são muito diferentes, vamos primeiramente padronizar as variáveis. Este passo não afeta a correlação, apenas como medimos a variabilidade.
den <- (density - mean(density))/sd(density)
res <- (residual.sugar - mean(residual.sugar))/sd(residual.sugar)
denres <- data.frame(den,res)
ggplot(denres,aes(den,res)) + geom_point(col="aquamarine4")Vamos obter a matriz de covariância das duas variáveis, \(\Sigma\).
## den res
## den 1.0000000 0.8389665
## res 0.8389665 1.0000000
Vamos calcular os autovetores, \(\gamma_1\) e \(\gamma_2\), os autovalores, \(\lambda_1\) e \(\lambda_2\), da matriz de covariância por meio da função eigen().
## eigen() decomposition
## $values
## [1] 1.8389665 0.1610335
##
## $vectors
## [,1] [,2]
## [1,] 0.7071068 -0.7071068
## [2,] 0.7071068 0.7071068
Seja \({\bf x}\) a variável bivariada representando as variáveis density e residual.sugar padronizadas.
Se definirmos uma nova variável \[ {\bf y} = \Gamma'{\bf x}, \] temos que a matriz de covariância de \({\bf y}\) é \(\Lambda\), pois \[ Var({\bf y}) = \Gamma'\Sigma\Gamma = \Gamma'\Gamma\Lambda\Gamma'\Gamma=\Lambda. \]
Componentes principais
A matriz \(\Gamma'\) (matriz de rotação) projeta \(\bf x\) nas direções de maior variabilidade de forma que as componentes de \(\bf y\) sejam não correlacionadas.
Tais direções são dadas pelos autovetores \(\gamma_1\) e \(\gamma_2\), que são ortogonais e denominadas componentes principais.
A primeira componente principal é o autovetor associado ao maior autovalor e a segunda componente principal é o autovetor associado ao segundo maior autovalor e assim por diante, caso houvesse mais de duas componentes principais.
ggplot(denres,aes(den,res)) + geom_point(col="aquamarine4") +
geom_segment(x=0,xend=0.7071,y=0,yend=0.7071,size=1.5) +
geom_segment(x=0,xend=-0.7071,y=0,yend=0.7071,size=1.5) +
coord_fixed() Podemos então projetar cada par de valores das variáveis density e residual.sugar
denres2 <- denres # declarando o novo data frame
for(i in 1:length(density)){
denres2[i,] <- t(Gamma)%*%as.numeric(denres[i,])
}
ggplot(denres2,aes(den,res)) + geom_point(col="cornflowerblue") +
coord_fixed() # escala originalA primeira componente explica a maior parte da variabilidade. Nesta caso, parece razoável considerar somente a primeira variável em termos das componentes principais e assim, reduzirmos a dimensão do banco de dados.
## [1] 0.9194832
O conjunto de dados representado por \(\bf y\) contém a mesma informação que o conjunto de dados representado por \(\bf x\), pois a tranformação é bijetiva.
Podemos obter \(\bf x\) de volta ao fazermos \[ {\bf z} = \Gamma {\bf y} = \Gamma \Gamma' {\bf x} = {\bf x.} \]
Análise de componentes principais
Podemos fazer uma ACP no R de maneira simples utilizando a função prcomp().
Para facilitar a visualização e análise dos resultados, vamos utilizar o pacote factoextra (Kassambara e Mundt 2020), que possui alguns gráficos úteis para a ACP.
Vamos chamá-lo.
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
Vamos utilizar a função prcomp() para fazermos a análise.
## Standard deviations (1, .., p=2):
## [1] 1.3560850 0.4012899
##
## Rotation (n x k) = (2 x 2):
## PC1 PC2
## den -0.7071068 -0.7071068
## res -0.7071068 0.7071068
## [1] "sdev" "rotation" "center" "scale" "x"
## PC1 PC2
## den -0.7071068 -0.7071068
## res -0.7071068 0.7071068
## PC1 PC2
## [1,] -3.6432511 0.34633181
## [2,] 0.6744540 -0.66150942
## [3,] -0.3244914 -0.18268544
## [4,] -0.6657604 -0.07783534
## [5,] -0.6657604 -0.07783534
## [6,] -0.3244914 -0.18268544
Vamos investigar a porcentagem da variabilidade explicada por cada componente.
Vamos investigar os elementos do banco de dados em termos das componentes principais.
No gráfico a seguir podemos ver a relação entre as componentes principais e as variáveis originais.
Variáveis positivamente correlacionadas apontam para o mesmo lado no gráfico.
Varáveis negativamente correlacionadas apontam para lados opostos.
As variáveis que mais contribuem para a componente principal apontam para o “lado” da componente (sentido positivo ou negativo).
O gráfico a seguir se chama biplot e combina as informações dos dois gráficos anteriores.
Análise de componentes principais (banco de dados completos)
Vamos agora fazer uma ACP para todo o banco de dados de vinho branco, com exceção da variável quality, que representa a nota dada ao vinho.
Primeiramente, como os valores das variáveis estão em escalas muito diferentes, padronizaremos todas.
## [1] "fixed.acidity" "volatile.acidity" "citric.acid"
## [4] "residual.sugar" "chlorides" "free.sulfur.dioxide"
## [7] "total.sulfur.dioxide" "density" "pH"
## [10] "sulphates" "alcohol"
white3 <- white2
for(i in 1:11){
med <- mean(white2[,i])
dp <- sd(white2[,i])
white3[,i] <- (white2[,i] - med)/dp # padronizando as variáveis
} Vamos prosseguir com a ACP.
## Standard deviations (1, .., p=11):
## [1] 1.7950638 1.2550856 1.1052924 1.0092187 0.9865772 0.9688867 0.8524072
## [8] 0.7741825 0.6435399 0.5380401 0.1436979
##
## Rotation (n x k) = (11 x 11):
## PC1 PC2 PC3 PC4
## fixed.acidity 0.157218451 -0.587558208 -0.1213683 -0.01858383
## volatile.acidity 0.005089494 0.051728054 0.5909715 -0.27411517
## citric.acid 0.144049843 -0.345294562 -0.5043969 -0.14851432
## residual.sugar 0.427408368 0.008749392 0.2143199 0.27376531
## chlorides 0.212011065 -0.008800308 0.1023674 -0.71071228
## free.sulfur.dioxide 0.300334387 0.290355136 -0.2794101 0.30558549
## total.sulfur.dioxide 0.406652203 0.244032391 -0.1243753 0.06045562
## density 0.511523597 0.006296796 0.1292029 0.02206110
## pH -0.128831885 0.581344397 -0.1266715 -0.09775335
## sulphates 0.043379327 0.222695370 -0.4332440 -0.44205953
## alcohol -0.437237835 -0.035568666 -0.1059032 0.14107870
## PC5 PC6 PC7 PC8 PC9
## fixed.acidity -0.25104839 -0.1035307 0.19784897 0.58835527 -0.33052283
## volatile.acidity -0.64261658 0.1223385 -0.26935495 0.02837266 0.14590968
## citric.acid -0.05390510 0.1320967 -0.70548123 -0.15228698 0.20201133
## residual.sugar -0.01139144 -0.2894469 -0.21275955 -0.38818585 -0.40896853
## chlorides 0.32862831 0.3958211 0.07948377 -0.10015094 -0.39353539
## free.sulfur.dioxide -0.17691226 0.4944936 0.16677879 -0.08179901 -0.14407339
## total.sulfur.dioxide -0.29300991 0.2763199 0.06772962 0.24731437 0.15454024
## density 0.08458824 -0.3276509 -0.11038544 0.06902650 -0.08788799
## pH 0.11982553 -0.1933412 -0.42731310 0.53388135 -0.26129767
## sulphates -0.40058526 -0.4810392 0.30856238 -0.27039413 0.01169757
## alcohol -0.33741948 0.1392842 -0.12892247 -0.19585929 -0.62109070
## PC10 PC11
## fixed.acidity -0.13170530 -0.171290475
## volatile.acidity -0.22372176 -0.017056659
## citric.acid -0.03735137 -0.009721121
## residual.sugar 0.09446795 -0.490225929
## chlorides 0.05337405 -0.025399445
## free.sulfur.dioxide -0.56745057 0.030908440
## total.sulfur.dioxide 0.70912033 -0.035560953
## density -0.06837403 0.759779368
## pH -0.11073292 -0.141197197
## sulphates -0.05770758 -0.041832843
## alcohol 0.27260860 0.357961330
Vamos investigar a porcentagem da variabilidade explicada por cada componente principal.
Vamos investigar porcentagem de variação acumulada.
dp <- acp$sdev
dpac <- cumsum(acp$sdev)/sum(acp$sdev) # cumsum retorna a soma acumulada
data.frame("dp"=dp,"porce"=paste(round(dpac*100,2),"%"))## dp porce
## 1 1.7950638 17.82 %
## 2 1.2550856 30.28 %
## 3 1.1052924 41.26 %
## 4 1.0092187 51.28 %
## 5 0.9865772 61.07 %
## 6 0.9688867 70.69 %
## 7 0.8524072 79.16 %
## 8 0.7741825 86.84 %
## 9 0.6435399 93.23 %
## 10 0.5380401 98.57 %
## 11 0.1436979 100 %
Vamos ver agora como as variaveis originais se relacionam com as duas componentes princiais.
Vamos prosseguir agora com o biplot. No gráfico, valores próximos são similares.
Podemos investigar agora se existe alguma relação aparente entre as componentes principais e as notas dos vinhos.
Com muitas notas possíveis, pode ser difícil verificar se há algum padrão. Vamos criar uma nova variável em que categorizamos os vinhos como “notas baixas” e “notas altas”.
Exemplo 6 - Serviços de utilidade pública
O banco de dados corresponde a variáveis associadas a 22 empresas de utilidade pública dos Estados Unidos.
Os dados estão disponíveis em Shmueli et al. (2017).
As variáveis são:
- Fixed - fixed-charge covering ratio (income/debt);
- RoR - rate of return on capital;
- Cost - cost per kilowatt capacity in place; Load = annual load factor;
- Demand - peak kilowatthour demand growth from 1974 to 1975;
- Sales - sales (kilowatthour use per year);
- Nuclear - percent nuclear;
- Fuel Cost - total fuel costs (cents per kilowatthour);
Importando o banco de dados
Arquivo com extensão .txt separado por tabulação
Vamos importar a base de dados.
uti <- read.csv("http://im.ufrj.br/~joao/cienciadedados/utilities.txt",sep="\t")
uti # vislumbre dos dados
names(uti) # # nomes das colunas do objeto (variáveis)## Company Fixed RoR Cost Load Demand Sales Nuclear
## 1 Arizona Public Service 1.06 9.2 151 54.4 1.6 9077 0.0
## 2 Boston Edison Co. 0.89 10.3 202 57.9 2.2 5088 25.3
## 3 Central Louisiana Co. 1.43 15.4 113 53.0 3.4 9212 0.0
## 4 Commonwealth Edison Co. 1.02 11.2 168 56.0 0.3 6423 34.3
## 5 Consolidated Edison Co. (NY) 1.49 8.8 192 51.2 1.0 3300 15.6
## 6 Florida Power & Light Co. 1.32 13.5 111 60.0 -2.2 11127 22.5
## 7 Hawaiian Electric Co. 1.22 12.2 175 67.6 2.2 7642 0.0
## 8 Idaho Power Co. 1.10 9.2 245 57.0 3.3 13082 0.0
## 9 Kentucky Utilities Co. 1.34 13.0 168 60.4 7.2 8406 0.0
## 10 Madison Gas & Electric Co. 1.12 12.4 197 53.0 2.7 6455 39.2
## 11 Nevada Power Co. 0.75 7.5 173 51.5 6.5 17441 0.0
## 12 New England Electric Co. 1.13 10.9 178 62.0 3.7 6154 0.0
## 13 Northern States Power Co. 1.15 12.7 199 53.7 6.4 7179 50.2
## 14 Oklahoma Gas & Electric Co. 1.09 12.0 96 49.8 1.4 9673 0.0
## 15 Pacific Gas & Electric Co. 0.96 7.6 164 62.2 -0.1 6468 0.9
## 16 Puget Sound Power & Light Co. 1.16 9.9 252 56.0 9.2 15991 0.0
## 17 San Diego Gas & Electric Co. 0.76 6.4 136 61.9 9.0 5714 8.3
## 18 The Southern Co. 1.05 12.6 150 56.7 2.7 10140 0.0
## 19 Texas Utilities Co. 1.16 11.7 104 54.0 -2.1 13507 0.0
## 20 Wisconsin Electric Power Co. 1.20 11.8 148 59.9 3.5 7287 41.1
## 21 United Illuminating Co. 1.04 8.6 204 61.0 3.5 6650 0.0
## 22 Virginia Electric & Power Co. 1.07 9.3 174 54.3 5.9 10093 26.6
## Fuel.cost
## 1 0.628
## 2 1.555
## 3 1.058
## 4 0.700
## 5 2.044
## 6 1.241
## 7 1.652
## 8 0.309
## 9 0.862
## 10 0.623
## 11 0.768
## 12 1.897
## 13 0.527
## 14 0.588
## 15 1.400
## 16 0.620
## 17 1.920
## 18 1.108
## 19 0.636
## 20 0.702
## 21 2.116
## 22 1.306
## [1] "Company" "Fixed" "RoR" "Cost" "Load" "Demand"
## [7] "Sales" "Nuclear" "Fuel.cost"
Análise exploratória
Box-plots das variáveis por empresa
Vamos ver o comportamento de cada variável por empresa.
a <- ggplot(uti,aes(Company,weight=Fixed)) + geom_bar(fill="khaki",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
b <- ggplot(uti,aes(Company,weight=RoR)) + geom_bar(fill="coral",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
c <- ggplot(uti,aes(Company,weight=Cost)) + geom_bar(fill="grey70",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
d <- ggplot(uti,aes(Company,weight=Load)) + geom_bar(fill="grey40",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
e <- ggplot(uti,aes(Company,weight=Demand)) + geom_bar(fill="orange",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
f <- ggplot(uti,aes(Company,weight=Sales)) + geom_bar(fill="blue",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
g <- ggplot(uti,aes(Company,weight=Nuclear)) + geom_bar(fill="yellow",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))
h <- ggplot(uti,aes(Company,weight=Fuel.cost)) + geom_bar(fill="grey70",col=1) + theme(axis.text.x=element_text(angle=45,hjust=1))Análise de componentes principais para identificação de agrupamentos
A ACP, além do seu papel de redução de dimensão, é útil para visualização de dados em alta dimensão por meio da representação destes em dimensões menores.
Assim, é possível utilizar a ACP para visualizar possíveis agrupamentos ou clusters.
Identificando agrupamentos visualmente
Vamos tentar identificar as empresas de serviço público que são semelhantes.
Em um primeiro passo, para facilitar a visualização, vamos nomear as linhas do data frame e encurtar o nome por meio da função word() do pacote stringr (Wickham 2019).
library("stringr")
uti2 <- uti[,-1] # retirando a coluna de nomes
nomes <- word(uti[,1]) # pegando a primeira palavra
nomes[c(12,17,18)] <- paste(nomes[c(12,17,18)],word(uti[c(12,17,18),1],2)) # acrescentando a segunda palavra em alguns nomes
nomes## [1] "Arizona" "Boston" "Central" "Commonwealth" "Consolidated"
## [6] "Florida" "Hawaiian" "Idaho" "Kentucky" "Madison"
## [11] "Nevada" "New England" "Northern" "Oklahoma" "Pacific"
## [16] "Puget" "San Diego" "The Southern" "Texas" "Wisconsin"
## [21] "United" "Virginia"
Vamos prosseguir com a ACP e investigar os resultados.
## Standard deviations (1, .., p=8):
## [1] 1.4740918 1.3785018 1.1504236 0.9983701 0.8056180 0.7560814 0.4652989
## [8] 0.4115657
##
## Rotation (n x k) = (8 x 8):
## PC1 PC2 PC3 PC4 PC5
## Fixed 0.44554526 -0.23217669 0.06712849 -0.55549758 0.4008403
## RoR 0.57119021 -0.10053490 0.07123367 -0.33209594 -0.3359424
## Cost -0.34869054 0.16130192 0.46733094 -0.40908380 0.2685680
## Load -0.28890116 -0.40918419 -0.14259793 -0.33373941 -0.6800711
## Demand -0.35536100 0.28293270 0.28146360 -0.39139699 -0.1626375
## Sales 0.05383343 0.60309487 -0.33199086 -0.19086550 -0.1319721
## Nuclear 0.16797023 -0.08536118 0.73768406 0.33348714 -0.2496462
## Fuel.cost -0.33584032 -0.53988503 -0.13442354 -0.03960132 0.2926660
## PC6 PC7 PC8
## Fixed -0.00654016 0.20578234 -0.48107955
## RoR -0.13326000 -0.15026737 0.62855128
## Cost 0.53750238 -0.11762875 0.30294347
## Load 0.29890373 0.06429342 -0.24781930
## Demand -0.71916993 -0.05155339 -0.12223012
## Sales 0.14953365 0.66050223 0.10339649
## Nuclear 0.02644086 0.48879175 -0.08466572
## Fuel.cost -0.25235278 0.48914707 0.43300956
Vamos investigar se existe alguma relação entre os grupos e sua região.
reg <- read.table("http://im.ufrj.br/~joao/cienciadedados/regioes.txt") # regiões de cada em empresa nos EUA
reg## V1
## 1 Oeste
## 2 Nordeste
## 3 Sul
## 4 Centro-Oeste
## 5 Nordeste
## 6 Sul
## 7 Oeste
## 8 Oeste
## 9 Sul
## 10 Centro-Oeste
## 11 Oeste
## 12 Nordeste
## 13 Centro-Oeste
## 14 Sul
## 15 Oeste
## 16 Oeste
## 17 Oeste
## 18 Sul
## 19 Sul
## 20 Centro-Oeste
## 21 Oeste
## 22 Sul
## Too few points to calculate an ellipse
Análise de componentes principais para previsão
Prevendo coordenadas
Vamos inicialmente considerar o conjunto de dados sem duas empresas: Puget Sound Power & Light Co. e Wisconsin Electric Power Co..
## Fixed RoR Cost Load Demand Sales Nuclear Fuel.cost
## Arizona 1.06 9.2 151 54.4 1.6 9077 0.0 0.628
## Boston 0.89 10.3 202 57.9 2.2 5088 25.3 1.555
## Central 1.43 15.4 113 53.0 3.4 9212 0.0 1.058
## Commonwealth 1.02 11.2 168 56.0 0.3 6423 34.3 0.700
## Consolidated 1.49 8.8 192 51.2 1.0 3300 15.6 2.044
## Florida 1.32 13.5 111 60.0 -2.2 11127 22.5 1.241
Vamos fazer a ACP sem essas duas empresas e investigar os resultados.
## Standard deviations (1, .., p=8):
## [1] 1.5183992 1.3274199 1.2201174 0.8931163 0.8217833 0.7689916 0.4917071
## [8] 0.3709790
##
## Rotation (n x k) = (8 x 8):
## PC1 PC2 PC3 PC4 PC5
## Fixed 0.32807762 -0.52457384 0.02740780 -0.3118825 0.10780600
## RoR 0.47988924 -0.34528770 0.08228092 -0.4079591 -0.03823866
## Cost -0.35311053 0.05387607 0.44875193 -0.2236685 0.67997558
## Load -0.37612743 -0.28612991 -0.32115981 -0.2723371 0.33497630
## Demand -0.30728174 0.27427882 0.20849305 -0.7082643 -0.51891188
## Sales 0.30328128 0.53393373 -0.26183688 -0.2041573 0.24423665
## Nuclear 0.03973451 -0.10849429 0.72388842 0.2396766 -0.11784750
## Fuel.cost -0.45599570 -0.38566906 -0.22784731 0.1064908 -0.26368662
## PC6 PC7 PC8
## Fixed -0.48725984 0.165081964 0.49281754
## RoR 0.33055559 -0.029403836 -0.60472158
## Cost -0.27228043 -0.004129898 -0.29066123
## Load 0.61919899 0.028182327 0.32083635
## Demand -0.04196668 -0.024029612 0.11676160
## Sales 0.03735313 0.671971333 0.01020928
## Nuclear 0.38193238 0.441341949 0.22505056
## Fuel.cost -0.21618981 0.569356172 -0.37368103
Queremos agora prever as coordenadas no gráfico das empresas que foram retiradas dos banco de dados utilizando apenas dados das empresas as quais consideramos anteriormente.
## Fixed RoR Cost Load Demand Sales Nuclear Fuel.cost
## Puget 1.16 9.9 252 56.0 9.2 15991 0.0 0.620
## Wisconsin 1.20 11.8 148 59.9 3.5 7287 41.1 0.702
Vamos projetar os valores das variáveis nas novas coordenadas.
## PC1 PC2 PC3 PC4 PC5 PC6
## Puget -0.3916282 2.3499131 0.6306031 -2.6119347 1.2889429 -1.053420
## Wisconsin 0.5401103 -0.6837701 1.3172558 -0.1064522 -0.2597302 1.300161
## PC7 PC8
## Puget 0.6368441 0.09037778
## Wisconsin 0.1812736 1.02826881
Agora vamos plotar os pontos previstos no biplot.
graf <- fviz_pca_biplot(acp,repel=TRUE,col.ind="cos2",gradient.cols=heat.colors(5))
fviz_add(graf,prev,repel=TRUE) # adicionado os novos pontosReferências
Auguie, B. 2017. gridExtra: Miscellaneous Functions for "Grid" Graphics. https://CRAN.R-project.org/package=gridExtra.
Cortez, P., A. Cerdeira, F. Almeida, T. Matos, e J. Reis. 2009. “Modeling wine preferences by data mining from physicochemical properties”. Decision Support Systems 47: 547–53.
Kassambara, A. 2019. ggcorrplot: Visualization of a Correlation Matrix using ’ggplot2’. https://CRAN.R-project.org/package=ggcorrplot.
Kassambara, A., e F. Mundt. 2020. factoextra: Extract and Visualize the Results of Multivariate Data Analyses. https://CRAN.R-project.org/package=factoextra.
Shmueli, G., P. C. Bruce, I. Yahav, N. R. Patel, e K. C. Lichtendahl Jr. 2017. Data mining for business analytics: concepts, techniques, and applications in R. John Wiley & Sons.
Wickham, H. 2016. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org.
———. 2019. stringr: Simple, Consistent Wrappers for Common String Operations. https://CRAN.R-project.org/package=stringr.
Wilkinson, L. 2012. “The grammar of graphics”. In Handbook of Computational Statistics, 375–414. Springer.